#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
"""FTP服务器GUI"""

import _thread
import os
from socket import *
from tkinter import (Button, Entry, Frame, Label, StringVar, Tk, filedialog, messagebox, Toplevel, IntVar, W, N,
                     ANCHOR, ttk, TOP, END)
from tkinter.ttk import Checkbutton
import pymysql
from pyftpdlib.authorizers import DummyAuthorizer
from pyftpdlib.handlers import FTPHandler
from pyftpdlib.servers import ThreadedFTPServer
from ttkbootstrap import Style


def alert_windows(alert_text):
    alert_window = Toplevel()
    alert_window.resizable(width=False, height=False)
    alert_window.transient()
    alert_window.wm_attributes('-topmost', 1)
    alert_window.geometry("220x140+655+350")
    alert_window.title("Alert")
    Label(alert_window, text=alert_text, font=16).pack(pady=30)
    Button(alert_window, text="确  定", font=16, width=8, height=1, command=alert_window.destroy).pack()


def user_udp():
    SERVERIP = '127.0.0.1'
    SERVERPORT = 6666
    BUFSIZE = 1024
    SERVERADDR = (SERVERIP, SERVERPORT)

    serverSock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)
    serverSock.bind(SERVERADDR)
    user = []
    for num in range(3):
        # 接收客户端的用户名、密码、ip
        byteRecvData, ADDRCLIENT = serverSock.recvfrom(BUFSIZE)
        print('收到客户端发来的以下信息：\n' + str(byteRecvData, encoding="utf8"))
        user.append(str(byteRecvData, encoding="utf8"))
    serverSock.sendto(bytes('1', encoding="utf8"), ADDRCLIENT)
    print('向客户端发送信息成功')
    serverSock.close()
    # 返回用户信息列表
    return user


class UserManager(Tk):
    def __init__(self):
        Tk.__init__(self)
        self.title("服务端")
        self.set_window_center(self, 620, 400)
        self.resizable(False, False)
        self.update()
        self.server = None
        self.server_thread = None
        self.running = StringVar()
        self.var_username = StringVar()
        self.var_passwd = StringVar()
        self.var_address = StringVar()
        self.var_port = IntVar()
        self.var_path = StringVar()  # 默认路径

        self.entry_username = None
        self.entry_passwd = None
        self.entry_address = None
        self.entry_port = None
        self.entry_path = None
        self.load_view()

    def set_window_center(self, window, width, height):
        """设置窗口宽高及居中"""
        # 获取屏幕 宽、高
        w_s = window.winfo_screenwidth()
        h_s = window.winfo_screenheight()
        # 计算 x, y 位置
        x_co = (w_s - width) / 2
        y_co = (h_s - height) / 2 - 50
        window.geometry("%dx%d+%d+%d" % (width, height, x_co, y_co))
        window.minsize(width, height)

    def load_view(self):
        def tree_color():  # 表格栏隔行显示不同颜色函数
            items = tree.get_children()  # 得到根目录所有行的iid
            i = 0  # 初值
            for hiid in items:
                if i / 2 != int(i / 2):  # 判断奇偶
                    tag1 = ''  # 奇数行
                else:
                    tag1 = 'even'  # 偶数行
                tree.item(hiid, tag=tag1)  # 偶数行设为浅蓝色的tag='even'
                i += 1  # 累加1 # 偶数行设为浅蓝色的tag='even'

        def user_list():
            sql2 = 'SELECT * FROM py_user'
            cursor.execute(sql2, {})
            result = cursor.fetchall()
            # 清空
            x = tree.get_children()
            for item in x:
                tree.delete(item)

            for person in result:
                tree.insert("", "end", values=(person['username'], person['password'],
                                               person['grand'], person['path']))
            tree_color()  # 上色

        # 用户列表
        var = Label(self, text="用户列表", font=('行楷', 15, 'bold'), pady=20)
        var.pack()
        tree = ttk.Treeview(self, show="headings", columns=("username", "password", "grand", "path"), height=12)  # 表格
        # 获取用户列表
        user_list()
        tree_color()

        # tree["columns"]=("id","name","age","tall")
        def fixed_map(option):
            return [elm for elm in style.map("Treeview", query_opt=option)
                    if elm[:2] != ("!disabled", "!selected")]

        def deljob():
            item = tree.selection()[0]
            my_tur = tree.item(item, "values")
            tree.delete(item)
            print(my_tur)
            # 数据库删除
            item_now = my_tur[0]
            print(item_now)
            sql3 = 'delete from py_user where username=%s'
            cursor.execute(sql3, item_now)
            # 记得提交
            connect.commit()
            tree_color()  # 背景颜色

        def grand_ftp():
            item = tree.selection()[0]
            my_tur = tree.item(item, "values")
            print(my_tur)
            # 数据库删除
            username = my_tur[0]

            def new_grand():
                # 获取选中情况
                grand = ''
                if news.get() == '1':
                    grand += 'N'
                if deletes.get() == '1':
                    grand += 'D'
                if uploads.get() == '1':
                    grand += 'U'
                if downloads.get() == '1':
                    grand += 'L'
                print('grand:' + grand)
                # 找到相符的用户信息，修改grand
                sql = 'update py_user set grand = %(grand)s where username=%(username)s'
                cursor.execute(sql, {'username': username, 'grand': grand}, )
                # result = cursor.fetchall()
                # 提交
                connect.commit()
                # cursor.close()
                # connect.close()
                alert_windows("修改权限成功！")
                grand_name.destroy()

            # 从数据库获取权限情况
            sql1 = 'SELECT `grand` FROM py_user where username=%(username)s'
            cursor.execute(sql1, {'username': username})
            result = cursor.fetchone()
            text = result["grand"]
            # 新建授权窗口
            grand_name = Toplevel()
            grand_name.resizable(width=False, height=False)
            grand_name.transient(manager)
            grand_name.wm_attributes('-topmost', 1)
            grand_name.geometry("280x160+635+370")
            grand_name.title("授权界面")

            news = StringVar()
            Checkbutton(grand_name, text="创建文件夹", variable=news).grid(row=0, sticky=W, padx=100, pady=3)
            deletes = StringVar()
            Checkbutton(grand_name, text="删除文件", variable=deletes).grid(row=1, sticky=W, padx=100, pady=3)
            uploads = StringVar()
            Checkbutton(grand_name, text="上传文件", variable=uploads).grid(row=2, sticky=W, padx=100, pady=3)
            downloads = StringVar()
            Checkbutton(grand_name, text="下载文件", variable=downloads).grid(row=3, sticky=W, padx=100, pady=3)
            # 可视化上次授权的选中情况
            if 'N' in text:
                news.set("1")
            if 'D' in text:
                deletes.set("1")
            if 'U' in text:
                uploads.set("1")
            if 'L' in text:
                downloads.set("1")
            Button(grand_name, text="授权", width=10, command=lambda: new_grand()) \
                .grid(row=4, sticky=N, padx=20, pady=10)

        style = Style(theme='united')
        style.map("Treeview", foreground=fixed_map("foreground"), background=fixed_map("background"))
        tree.tag_configure('even', background='#FAEBD7')
        tree_color()
        tree.column("username", width=70, anchor="center")  # 表示列
        tree.column("password", width=50, anchor="center")
        tree.column("grand", width=50, anchor="center")
        tree.column("path", width=400, anchor="center")
        tree.heading("username", text="用户名")  # 显示表头
        tree.heading("password", text="密码")
        tree.heading("grand", text="权限")
        tree.heading("path", text="根目录")
        tree.pack()

        Label(self, text="注：N（新建文件夹）、D（删除）、U（上传）、L（下载）").pack(side=TOP)
        btn_box = Frame(self, relief="ridge", borderwidth=1)
        btn_box.pack()
        self.btn_add = Button(
            btn_box, text="添加", width=10, command=self.my_ftp)
        self.btn_add.pack(side="left", padx=20, pady=20)
        self.btn_grand = Button(
            btn_box, text="授权", width=10, command=grand_ftp)
        self.btn_grand.pack(side="left", padx=20)
        self.btn_running = Button(
            btn_box, text="启动服务器", width=15, command=run_ftp)
        self.btn_running.pack(side="left", padx=20)
        # self.btn_stop = Button(
        #     btn_box, text="停止", command=stop_ftp)
        # self.btn_stop.pack(side="left", padx=20)
        self.btn_delete = Button(
            btn_box, text="删除", width=10, command=deljob)
        self.btn_delete.pack(side="left", padx=20)
        self.btn_flash = Button(
            btn_box, text="刷新", width=10, command=user_list)
        self.btn_flash.pack(side="left", padx=20)

    def show(self):
        self.update()
        self.deiconify()

    def hide(self):
        self.withdraw()

    def my_ftp(self):
        def selectPath():
            path = filedialog.askdirectory()
            if os.path.isdir(path):
                entry_path.delete(0, END)
                entry_path.insert(0, path)

        def new_user():
            sql4 = 'insert into py_user(username,password,path) values(%(username)s,%(password)s,%(path)s)'
            username = var_username.get()
            password = var_passwd.get()
            path = var_path.get()
            cursor.execute(sql4, {'username': username, 'password': password, 'path': path})
            connect.commit()
            alert_windows("添加成功！")

        var_username = StringVar()
        var_passwd = StringVar()
        var_path = StringVar()  # 默认路径
        entry_path = None

        self.withdraw()
        root = Toplevel()
        root.title("添加用户")
        root.geometry('412x300+500+250')  # 改变窗口位置和大小
        manager.hide()
        """界面"""
        Label(root, text="账号:").pack(side=TOP, pady=10)
        entry_username = Entry(root, textvariable=var_username, bd=2)
        entry_username.pack(anchor='center')

        Label(root, text="密码:").pack(anchor='center', pady=10)
        entry_passwd = Entry(root, textvariable=var_passwd, bd=2)
        entry_passwd.pack(anchor='center')

        Label(root, text="路径:").pack(anchor='center', pady=10)
        entry_path = Entry(root, textvariable=var_path, bd=2)
        entry_path.pack(anchor='center')

        btn_select_path = Button(root, text="选择", height=1, command=selectPath)
        btn_select_path.pack(anchor='center', pady=10)

        btn_box = Frame(root, relief="ridge", height=1)
        btn_box.pack(anchor='center')
        btn_start = Button(btn_box, text="提交", width=15, command=new_user)
        btn_start.pack(side="left", padx=20)
        btn_stop = Button(
            btn_box, text="返回", width=15, command=manager.show)
        btn_stop.pack(side="right", padx=20)


def run_ftp():
    alert_windows("服务器已启动！")
    if os.path.isdir('C:/Users/WindRide/Desktop') is not True:
        messagebox.showerror(title="提示", message="路径不对")
        return
    _thread.start_new_thread(ftpserver, ())
    # fixed_entry("readonly")


def stop_ftp(self):
    self.fixed_entry()
    if self.server:
        try:
            self.server.close()
        #     cursor.close()
        #     connect.close()
        except Exception:
            print(Exception)


def ftpserver():
    # 接收客户端的信息，1代表用户存在
    data = user_udp()
    print(data)
    # 实例化虚拟用户，这是FTP验证首要条件
    authorizer = DummyAuthorizer()
    # 填入从客服端传来的账号
    username = data[0]
    password = data[1]
    sql = 'SELECT `path` FROM py_user where username=%(username)s and password=%(password)s'
    cursor.execute(sql, {'username': username, 'password': password})
    user_path = cursor.fetchall()
    print(user_path[0]['path'])
    # 添加用户权限和路径，括号内的参数是(用户名， 密码， 用户目录， 权限)
    authorizer.add_user(
        data[0],
        data[1],
        user_path[0]['path'],
        perm="elradfmwMT")

    # 添加匿名用户，任何人都可以访问，否则需要输入用户名和密码才能访问
    # 匿名用户只需要配置路径
    authorizer.add_anonymous('C:/Users/WindRide/Desktop/LearnWork/MyFTP/xie', msg_login="Welcome")

    # 初始化ftp句柄
    handler = FTPHandler
    handler.authorizer = authorizer

    # 监听ip和端口
    server = ThreadedFTPServer(
        ('127.0.0.1', '21'), handler)

    # 开始服务
    server.serve_forever()


if __name__ == "__main__":
    connect = pymysql.Connect(host='localhost', user='root', password='root', database='school')
    cursor = connect.cursor(cursor=pymysql.cursors.DictCursor)
    manager = UserManager()
    manager.encoding = 'utf-8'
    style = Style(theme='united')
    manager.mainloop()
